package com.youlin.aop;

import com.youlin.dto.Status;
import com.youlin.security.SecurityUser;
import com.youlin.untils.AdminUtil;
import com.youlin.untils.RedisUtil;
import com.youlin.untils.TokenIntercept;
import com.youlin.untils.UnIntercept;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Autowired
    private SessionRegistry sessionRegistry;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        System.out.printf("LoginInterceptor ===>> %s \n", CrossFilter.fastThreadLocal.get());
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Package aPackage = handlerMethod.getBean().getClass().getPackage();
            if (! aPackage.getName().startsWith("com.youlin")) return true;
            Method method = handlerMethod.getMethod();
            UnIntercept unIntercept = method.getAnnotation(UnIntercept.class);
            if (unIntercept != null) return true;
            TokenIntercept tokenIntercept = method.getAnnotation(TokenIntercept.class);
            if (tokenIntercept != null) {
                Class<?> returnType = method.getReturnType();
                Constructor<?> constructor = returnType.getConstructor(Status.class);
                String takerToken = request.getHeader("takerToken");
                request.setAttribute("Constructor", constructor);
                if (StringUtils.isBlank(takerToken) || ! redisTemplate.hasKey("takerToken:" + takerToken)) {
                    request.getRequestDispatcher("/common/tokenLogin").forward(request, response);
                    return false;
                } else {
                    RedisUtil.addExpire(redisTemplate, "takerToken:" + takerToken);
                    return true;
                }
            }
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null) {
                Cookie[] cookies = request.getCookies();
                for (Cookie cookie: cookies)
                    if (cookie.getName().equals("JSESSIONID"))
                        if (! AdminUtil.findUser(sessionRegistry, cookie.getValue())) {
                            request.getRequestDispatcher("/common/toLogin").forward(request, response);
                            return false;
                        }
                SecurityUser securityUser = (SecurityUser) authentication.getPrincipal();
                if (BooleanUtils.isTrue(securityUser.bygAdmin.getReset())) {
                    request.getRequestDispatcher("/common/updPwdFirst").forward(request, response);
                    return false;
                }
            }
        }
        return true;
	}

    @Override
    public void postHandle(HttpServletRequest httpServletRequest,
                           HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest,
                                HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }

}
